package com.thank.concurrency.samples.count;

import com.thank.concurrency.annoations.NotThreadSafe;
import com.thank.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * @author thank
 * 演示使用volatile修饰变量
 */
@Slf4j
@NotThreadSafe
public class CountExample4 {

    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    public static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException {

//        ExecutorService executorService = Executors.newCachedThreadPool()

        // 阿里规范方式创建线程池
        ExecutorService executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
                new SynchronousQueue<>(), r -> new Thread(r, "测试线程"));

        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception: ", e);
                }
                countDownLatch.countDown();
            });
        }

        countDownLatch.await();
        executorService.shutdown();
        log.info("count: {}", count);
    }

    private static void add() {
        // 虽然count被volatile修饰, 保证每次都从主内存中取值, 但是依然无法保证计数的线程安全
        // 因为count ++被分为了三步: 1. 取出内存中的count值, 2. +1, 3. 写回主存
        // 在这三步之间多个线程时可能会同时进来导致线程不安全
        count ++;
    }
}
